package com.wang.gallerybackend.controller;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.wang.gallerybackend.annotation.AuthCheck;
import com.wang.gallerybackend.api.aliyunai.AliYunAiApi;
import com.wang.gallerybackend.api.aliyunai.model.CreateOutPaintingTaskResponse;
import com.wang.gallerybackend.api.aliyunai.model.GetOutPaintingTaskResponse;
import com.wang.gallerybackend.api.imagesearch.imageSearchApiFacade;
import com.wang.gallerybackend.api.imagesearch.model.ImageSearchResult;
import com.wang.gallerybackend.common.AjaxResult;
import com.wang.gallerybackend.common.BaseResponse;
import com.wang.gallerybackend.common.DeleteRequest;
import com.wang.gallerybackend.constant.UserConstant;
import com.wang.gallerybackend.exception.BusinessException;
import com.wang.gallerybackend.exception.ErrorCode;
import com.wang.gallerybackend.exception.ThrowUtils;
import com.wang.gallerybackend.manager.RedisManger;
import com.wang.gallerybackend.manager.auth.SpaceUserAuthManager;
import com.wang.gallerybackend.manager.auth.StpKit;
import com.wang.gallerybackend.manager.auth.annotation.SaSpaceCheckPermission;
import com.wang.gallerybackend.manager.auth.model.SpaceUserPermission;
import com.wang.gallerybackend.manager.auth.model.SpaceUserPermissionConstant;
import com.wang.gallerybackend.model.dto.picture.*;
import com.wang.gallerybackend.model.entity.Picture;
import com.wang.gallerybackend.model.entity.Space;
import com.wang.gallerybackend.model.entity.User;
import com.wang.gallerybackend.model.enums.PictureReviewStatusEnum;
import com.wang.gallerybackend.model.vo.PictureTagCategory;
import com.wang.gallerybackend.model.vo.PictureVO;
import com.wang.gallerybackend.service.PictureService;
import com.wang.gallerybackend.service.SpaceService;
import com.wang.gallerybackend.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author 汪
 */
@Slf4j
@RestController
@RequestMapping("/file")
public class PictureController {


	@Resource
	private UserService userService;
	@Resource
	private PictureService pictureService;
	@Resource
	private RedisManger redisManger;
	@Resource
	private SpaceService spaceService;
	@Resource
	private AliYunAiApi aliYunAiApi;
	/**
	 *本地缓存
	 */
	private final Cache<String, String> LOCAL_CACHE = Caffeine.newBuilder()
			.initialCapacity(1024)
			.maximumSize(10_000L)
			.expireAfterWrite(Duration.ofMinutes(5))
			.build();
	@Autowired
	private SpaceUserAuthManager spaceUserAuthManager;

	/**
	 * 更新图片（仅管理员可用）
	 *
	 * @param pictureUpdateRequest 图片更新参数
	 * @return 响应
	 */
	@PostMapping("/update")
	@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
	public BaseResponse<Boolean> updatePicture(@RequestBody PictureUpdateRequest pictureUpdateRequest,
											   HttpServletRequest request) {
		//获取用户
		User loginUser = userService.getLoginUser(request);
		if (pictureUpdateRequest == null || pictureUpdateRequest.getId() <= 0) {
			throw new BusinessException(ErrorCode.PARAMS_ERROR);
		}
		// 将实体类和 DTO 进行转换
		Picture picture = new Picture();
		BeanUtils.copyProperties(pictureUpdateRequest, picture);
		// 注意将 list 转为 string
		picture.setTags(JSONUtil.toJsonStr(pictureUpdateRequest.getTags()));
		// 数据校验
		pictureService.validPicture(picture);
		// 判断是否存在
		long id = pictureUpdateRequest.getId();
		Picture oldPicture = pictureService.getById(id);
		ThrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR);
		//补充审核参数
		pictureService.fillReviewParams(picture, loginUser);
		// 操作数据库
		boolean result = pictureService.updateById(picture);
		ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);

		return AjaxResult.success(true);
	}

	/**
	 * 上传图片
	 * @param multipartFile 图片文件
	 * @return 图片信息
	 */
	@PostMapping("/upload")
	@SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_UPLOAD)
	public BaseResponse<PictureVO> uploadPicture(@RequestPart("file") MultipartFile multipartFile
			, PictureUploadDTO pictureUploadDTO, HttpServletRequest request) {
		User loginUser = userService.getLoginUser(request);
		PictureVO pictureVO = pictureService.uploadPicture(multipartFile, pictureUploadDTO, loginUser);
		return AjaxResult.success(pictureVO);
	}

	/**
	 * 上传图片(通过url上传图片)
	 * @return 图片信息
	 */
	@PostMapping("/upload/url")
	@SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_UPLOAD)
	public BaseResponse<PictureVO> uploadPictureByUrl(@RequestBody PictureUploadDTO pictureUploadDTO, HttpServletRequest request) {
		User loginUser = userService.getLoginUser(request);
		String fileUrl = pictureUploadDTO.getFileUrl();
		PictureVO pictureVO = pictureService.uploadPicture(fileUrl, pictureUploadDTO, loginUser);
		return AjaxResult.success(pictureVO);
	}


	/**
	 * 删除图片
	 * @param deleteRequest 删除参数
	 * @return 响应
	 */
	@PostMapping("/delete")
	@SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_DELETE)
	public BaseResponse<Boolean> deletePicture(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
		if (deleteRequest == null || deleteRequest.getId() <= 0) {
			throw new BusinessException(ErrorCode.PARAMS_ERROR);
		}
		User loginUser = userService.getLoginUser(request);
		pictureService.deletePicture(deleteRequest.getId(), loginUser);
		return AjaxResult.success(true);
	}

	/**
	 * 根据 id 获取图片（仅管理员可用）
	 */
	@GetMapping("/get")
	@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
	public BaseResponse<Picture> getPictureById(long id) {
		ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
		// 查询数据库
		Picture picture = pictureService.getById(id);
		ThrowUtils.throwIf(picture == null, ErrorCode.NOT_FOUND_ERROR);
		// 获取封装类
		return AjaxResult.success(picture);
	}

	/**
	 * 根据 id 获取图片（封装类）
	 */
	@GetMapping("/get/vo")
	public BaseResponse<PictureVO> getPictureVOById(Long id, HttpServletRequest request) {
		ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);
		//查询数据库
		Picture picture = pictureService.getById(id);
		ThrowUtils.throwIf(picture == null, ErrorCode.NOT_FOUND_ERROR);
		PictureVO pictureVO = pictureService.getPictureVO(picture, request);
		// 空间权限校验
		Long spaceId = picture.getSpaceId();
		Space space = null;
		if (spaceId != null) {
			//编程式注解校验权限
			boolean hasPermission = StpKit.SPACE.hasPermission(SpaceUserPermissionConstant.PICTURE_VIEW);
			ThrowUtils.throwIf(!hasPermission, ErrorCode.NOT_AUTH_ERROR);
			//改为使用注解鉴权
			/*pictureService.checkPictureAuth(picture, loginUser);*/
			space = spaceService.getById(spaceId);
		}
		User loginUser = userService.getLoginUser(request);
		List<String> permissionList = spaceUserAuthManager.getPermissionList(space, loginUser);
		pictureVO.setPermissionList(permissionList);
		// 获取封装类
		return AjaxResult.success(pictureVO);
	}

	/**
	 * 分页获取图片列表（仅管理员可用）
	 */
	@PostMapping("/list/page")
	@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
	public BaseResponse<Page<Picture>> listPictureByPage(@RequestBody PictureQueryRequest pictureQueryRequest) {
		long current = pictureQueryRequest.getPageNum();
		long size = pictureQueryRequest.getPageSize();
		// 查询数据库
		Page<Picture> picturePage = pictureService.page(new Page<>(current, size),
				pictureService.getQueryWrapper(pictureQueryRequest));
		return AjaxResult.success(picturePage);
	}

	/**
	 * 分页获取图片列表（封装类）
	 */
	@PostMapping("/list/page/vo")
	public BaseResponse<Page<PictureVO>> listPictureVOByPage(@RequestBody PictureQueryRequest pictureQueryRequest,
															 HttpServletRequest request) {
		long current = pictureQueryRequest.getPageNum();
		long size = pictureQueryRequest.getPageSize();
		// 限制爬虫
		ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
		// 只展示审核通过的图片
		pictureQueryRequest.setReviewStatus(PictureReviewStatusEnum.REVIEW_PASS.getValue());
		// 空间权限校验
		Long spaceId = pictureQueryRequest.getSpaceId();
		if (spaceId == null) {
			// 公开图库
			pictureQueryRequest.setNullSpaceId(true);
			pictureQueryRequest.setReviewMessage(PictureReviewStatusEnum.REVIEW_PASS.getText());
		} else {
			//编程式注解校验权限
			boolean hasPermission = StpKit.SPACE.hasPermission(SpaceUserPermissionConstant.PICTURE_VIEW);
			ThrowUtils.throwIf(!hasPermission, ErrorCode.NOT_AUTH_ERROR);
			// 私有图库
//			User loginUser = userService.getLoginUser(request);
//			Space space = spaceService.getById(spaceId);
//			ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
//			if (!loginUser.getId().equals(space.getUserId())) {
//				throw new BusinessException(ErrorCode.NOT_AUTH_ERROR);
//			}
		}
		// 查询数据库
		Page<Picture> picturePage = pictureService.page(new Page<>(current, size),
				pictureService.getQueryWrapper(pictureQueryRequest));
		// 获取封装类
		return AjaxResult.success(pictureService.getPictureVOPage(picturePage, request));
	}

	/**
	 * 分页获取图片列表（封装类,有缓存）
	 */
	@PostMapping("/list/page/vo/cache")
	public BaseResponse<Page<PictureVO>> listPictureVOByPageWithCache(@RequestBody PictureQueryRequest pictureQueryRequest,
																	  HttpServletRequest request) {
		long current = pictureQueryRequest.getPageNum();
		long size = pictureQueryRequest.getPageSize();
		// 限制爬虫
		ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
		// 只展示审核通过的图片
		pictureQueryRequest.setReviewStatus(PictureReviewStatusEnum.REVIEW_PASS.getValue());
		//查询缓存，缓存中没有，则查询数据库
		//构建缓存的key
		String queryCondition = JSONUtil.toJsonStr(pictureQueryRequest);
		String hashKey = DigestUtils.md5DigestAsHex(queryCondition.getBytes());
		String cacheKey = String.format("wang:listPictureVOByPage:%s", hashKey);
		Page<PictureVO> result = redisManger.getWithCache(
				cacheKey,
				() -> {
					Page<Picture> picturePage = pictureService.page(new Page<>(current, size),
							pictureService.getQueryWrapper(pictureQueryRequest));
					return pictureService.getPictureVOPage(picturePage, request);
				},
				300 + RandomUtil.randomInt(0, 300), Page.class
		);
		// 获取封装类
		return AjaxResult.success(result);
	}

	/**
	 * 编辑图片（给用户使用）
	 */
	@PostMapping("/edit")
	@SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_EDIT)
	public BaseResponse<Boolean> editPicture(@RequestBody PictureEditRequest pictureEditRequest, HttpServletRequest request) {
		if (pictureEditRequest == null || pictureEditRequest.getId() <= 0) {
			throw new BusinessException(ErrorCode.PARAMS_ERROR);
		}
		User loginUser = userService.getLoginUser(request);
		pictureService.editPicture(pictureEditRequest, loginUser);
		return AjaxResult.success(true);
	}

	@GetMapping("/tag_category")
	public BaseResponse<PictureTagCategory> listPictureTagCategory() {
		PictureTagCategory pictureTagCategory = new PictureTagCategory();
		List<String> tagList = Arrays.asList("热门", "搞笑", "生活", "高清", "艺术", "校园", "背景", "简历", "创意");
		List<String> categoryList = Arrays.asList("模板", "电商", "表情包", "素材", "海报");
		pictureTagCategory.setTagList(tagList);
		pictureTagCategory.setCategoryList(categoryList);
		return AjaxResult.success(pictureTagCategory);
	}

	/**
	 * 审核图片
	 */
	@PostMapping("/review")
	@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
	public BaseResponse<Boolean> doPictureReview(@RequestBody PictureReviewRequest pictureReviewRequest,
												 HttpServletRequest request) {
		if (pictureReviewRequest == null) {
			throw new BusinessException(ErrorCode.PARAMS_ERROR);
		}
		User loginUser = userService.getLoginUser(request);
		pictureService.doPictureReview(pictureReviewRequest, loginUser);
		return AjaxResult.success(true);
	}

	/**
	 * 批量上传图片
	 */
	@PostMapping("/upload/batch")
	@AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
	public BaseResponse<Integer> uploadPictureByBitch(@RequestBody PictureUploadByBatchRequest pictureUploadByBatchRequest, HttpServletRequest request) {
		ThrowUtils.throwIf(pictureUploadByBatchRequest == null, ErrorCode.PARAMS_ERROR);
		User loginUser = userService.getLoginUser(request);
		return AjaxResult.success(pictureService.uploadPictureByBitch(pictureUploadByBatchRequest, loginUser));
	}

	/**
	 * 以图搜图
	 */
	@PostMapping("/search/picture/so")
	@SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_VIEW)
	public BaseResponse<List<ImageSearchResult>> searchPictureByPictureIsSo(@RequestBody SearchPictureByPictureRequest searchPictureByPictureRequest) {
		ThrowUtils.throwIf(searchPictureByPictureRequest == null, ErrorCode.PARAMS_ERROR);
		Long pictureId = searchPictureByPictureRequest.getPictureId();
		ThrowUtils.throwIf(pictureId == null || pictureId <= 0, ErrorCode.PARAMS_ERROR);
		Picture oldPicture = pictureService.getById(pictureId);
		ThrowUtils.throwIf(oldPicture == null, ErrorCode.NOT_FOUND_ERROR);
		List<ImageSearchResult> resultList = new ArrayList<>();
		// 这个 start 是控制查询多少页, 每页是 20 条
		int start = 0;
		while (resultList.size() <= 50) {
			List<ImageSearchResult> tempList = imageSearchApiFacade.searchImage(
					StrUtil.isNotBlank(oldPicture.getUrl()) ? oldPicture.getUrl() : oldPicture.getUrl(), start
			);
			if (tempList.isEmpty()) {
				break;
			}
			resultList.addAll(tempList);
			start += tempList.size();
		}
		return AjaxResult.success(resultList);
	}

	/**
	 * 以色搜图
	 */
	@PostMapping("/search/picture/color")
	@SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_VIEW)
	public BaseResponse<List<PictureVO>> searchPictureByColor(@RequestBody SearchPictureByColorRequest searchPictureByColorRequest,
															  HttpServletRequest request) {
		//获取当前用户
		User loginUser = userService.getLoginUser(request);
		ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR);
		ThrowUtils.throwIf(searchPictureByColorRequest == null, ErrorCode.PARAMS_ERROR);
		Long spaceId = searchPictureByColorRequest.getSpaceId();
		String picColor = searchPictureByColorRequest.getPicColor();
		List<PictureVO> pictureVOS = pictureService.searchPictureByColor(spaceId, picColor, loginUser);
		return AjaxResult.success(pictureVOS);
	}

	/**
	 * 批量编辑图片
	 */
	@PostMapping("/edit/batch")
	@SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_EDIT)
	public BaseResponse<Boolean> editPictureByBatch(@RequestBody PictureEditByBatchRequest pictureEditByBatchRequest, HttpServletRequest request) {
		if (pictureEditByBatchRequest == null) {
			throw new BusinessException(ErrorCode.PARAMS_ERROR);
		}
		User loginUser = userService.getLoginUser(request);
		pictureService.editPictureByBatch(pictureEditByBatchRequest, loginUser);
		return AjaxResult.success(true);
	}

	/**
	 * 创建图片扩图任务
	 */
	@PostMapping("/out_painting/create_task")
	@SaSpaceCheckPermission(value = SpaceUserPermissionConstant.PICTURE_EDIT)
	public BaseResponse<CreateOutPaintingTaskResponse> createPictureOutPaintingTask(@RequestBody CreatePictureOutPaintingTaskRequest createPictureOutPaintingTaskRequest,
																					HttpServletRequest request) {
		ThrowUtils.throwIf(createPictureOutPaintingTaskRequest == null
				|| createPictureOutPaintingTaskRequest.getPictureId() == null, ErrorCode.PARAMS_ERROR);
		User loginUser = userService.getLoginUser(request);
		return AjaxResult.success(
				pictureService.createPictureOutPaintingTask
						(createPictureOutPaintingTaskRequest, loginUser));

	}


	/**
	 * 查询图片扩图任务结果
	 */
	@GetMapping("/out_painting/get_task")
	public BaseResponse<GetOutPaintingTaskResponse> getPictureOutPaintingTaskResult(
			String taskId) {
		ThrowUtils.throwIf(taskId == null, ErrorCode.PARAMS_ERROR);
		GetOutPaintingTaskResponse outPaintingTask = aliYunAiApi.getOutPaintingTask(taskId);
		return AjaxResult.success(outPaintingTask);
	}
}
